home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / modes / lazy-shot.el.z / lazy-shot.el
Encoding:
Text File  |  1998-05-21  |  11.0 KB  |  312 lines

  1. ;;; lazy-shot.el --- Lazy font locking for XEmacs
  2.  
  3. ;; Copyright (C) 1997 Jan Vroonhof
  4.  
  5. ;; Author: Jan Vroonhof <vroonhof@math.ethz.ch>
  6. ;; Keywords: languages, faces
  7.  
  8. ;; This file is part of XEmacs
  9.  
  10. ;; XEmacs is free software; you can redistribute it and/or modify it
  11. ;; under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation; either version 2, or (at your option)
  13. ;; any later version.
  14.  
  15. ;; XEmacs is distributed in the hope that it will be useful, but
  16. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18. ;; General Public License for more details.
  19.  
  20. ;; You should have received a copy of the GNU General Public License
  21. ;; along with XEmacs; see the file COPYING.  If not, write to the 
  22. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  23. ;; Boston, MA 02111-1307, USA.
  24.  
  25. ;;; Synched up with:  Not in FSF (mostly equivalent to lazy-lock 2.09
  26. ;;; in FSF 20.2).
  27.  
  28. ;;; Commentary:
  29.  
  30. ;;; This is an experimental demand based font-lock implemenation.  It
  31. ;;; is almost equal in functionality and interface to lazy-lock 2.09
  32. ;;; Does somebody really need defer-locking?
  33. ;;;
  34. ;;; To use: put
  35. ;;;    (add-hook 'font-lock-mode-hook 'turn-on-lazy-shot)
  36. ;;; in .emacs (.xemacs/init.el).  Do not use in combination with
  37. ;;; lazy-lock.
  38.  
  39. ;;; It is exprimental in the sense that it relies on C support from
  40. ;;; the redisplay engine, that is experimental.  The code in this file
  41. ;;; is more or less finished.  The C code support experimental because
  42. ;;; the current design is rumoured to be ugly.  Secondly because
  43. ;;; XEmacs does actually display the "un-font-locked" parts of the
  44. ;;; buffer first, the user notices flashing as the buffer is repainted 
  45. ;;; with color/fonts.
  46.  
  47. ;;; Code:
  48.  
  49. (require 'font-lock)
  50. (require 'itimer)
  51.  
  52. (defvar lazy-shot-mode nil)
  53. (defvar lazy-shot-stealth-timer nil)
  54.  
  55.  
  56. (defgroup lazy-shot nil
  57.   "Lazy-shot customizations"
  58.   :group 'tools
  59.   :group 'faces
  60.   :prefix "lazy-shot-")
  61.  
  62. (defcustom lazy-shot-minimum-size 0
  63.     "*Minimum size of a buffer for demand-driven fontification.
  64. On-demand fontification occurs if the buffer size is greater than this value.
  65. If nil, means demand-driven fontification is never performed."
  66.     :type '(choice (const :tag "Off" nil)
  67.            (integer :tag "Size"))
  68.     :group 'lazy-shot)
  69.  
  70.  
  71. (defcustom lazy-shot-step-size 1024    ; Please test diffent sizes
  72.   "Minimum size of each fontification shot."
  73.   :type 'integer
  74.   :group 'lazy-shot)
  75.  
  76. (defcustom lazy-shot-stealth-time 30
  77.   "*Time in seconds to delay before beginning stealth fontification.
  78. Stealth fontification occurs if there is no input within this time.
  79. If nil, means stealth fontification is never performed.
  80.  
  81. The value of this variable is used when Lazy Shot mode is turned on."
  82.   :type '(choice (const :tag "Off" nil)
  83.          (number :tag "Time"))
  84.   :group 'lazy-shot)
  85.  
  86. (defcustom lazy-shot-stealth-lines (if font-lock-maximum-decoration 100 250)
  87.   "*Maximum size of a chunk of stealth fontification.
  88. Each iteration of stealth fontification can fontify this number of lines.
  89. To speed up input response during stealth fontification, at the cost of stealth
  90. taking longer to fontify, you could reduce the value of this variable."
  91.   :type 'integer
  92.   :group 'lazy-shot)
  93.  
  94. (defcustom lazy-shot-stealth-nice
  95.    (/ (float 1) (float 8))
  96.   "*Time in seconds to pause between chunks of stealth fontification.
  97. Each iteration of stealth fontification is separated by this amount of time.
  98. To reduce machine load during stealth fontification, at the cost of stealth
  99. taking longer to fontify, you could increase the value of this variable."
  100.   :type 'number
  101.   :group 'lazy-shot)
  102.  
  103. (defcustom lazy-shot-verbose (not (null font-lock-verbose))
  104.   "*If non-nil, means demand fontification should show status messages."
  105.   :type 'boolean
  106.   :group 'lazy-shot)
  107.  
  108. (defcustom lazy-shot-stealth-verbose (not (null lazy-shot-verbose))
  109.   "*If non-nil, means stealth fontification should show status messages."
  110.   :type 'boolean
  111.   :group 'lazy-shot)
  112.  
  113.  
  114.  
  115. ;;;###autoload
  116. (defun lazy-shot-mode (&optional arg)
  117.   "Toggle Lazy Lock mode.
  118. With arg, turn Lazy Lock mode on if and only if arg is positive."
  119.   (interactive "P")
  120.   (let ((was-on lazy-shot-mode))
  121.     (set (make-local-variable 'lazy-shot-mode)
  122.      (and (if arg (> (prefix-numeric-value arg) 0) (not lazy-shot-mode))))
  123.     (cond ((and lazy-shot-mode (not font-lock-mode))
  124.        ;; Turned on `lazy-shot-mode' rather than `font-lock-mode'.
  125.        (let ((font-lock-support-mode 'lazy-shot-mode))
  126.          (font-lock-mode t)))
  127.       (lazy-shot-mode
  128.        ;; Turn ourselves on.
  129.        (lazy-shot-install))
  130.       (was-on
  131.        ;; Turn ourselves off.
  132.        (lazy-shot-unstall)))))
  133.  
  134. (custom-add-option 'font-lock-mode-hook 'turn-on-lazy-shot)
  135.  
  136. ;;;###autoload
  137. (defun turn-on-lazy-shot ()
  138.   "Unconditionally turn on Lazy Lock mode."
  139.   (lazy-shot-mode t))
  140.  
  141.   ;; Can we do something intelligent here?
  142.   ;; I would want to set-extent-end-position start on extents that
  143.   ;; only partially overlap!
  144. (defun lazy-shot-clean-up-extents (start end)
  145.   "Make sure there are no lazy-shot-extens betweeen START and END.
  146. This improves efficiency and C-g behavior."
  147.   ;; Be carefull this function is typically called with inhibit-quit!
  148.   (map-extents (lambda (e b) (delete-extent e))
  149.            nil start end nil 'start-and-end-in-region 'initial-redisplay-function
  150.            'lazy-shot-redisplay-function))
  151.              
  152. (defun lazy-shot-redisplay-function (extent)
  153.    "Lazy lock the EXTENT when it has become visisble."
  154.    (lazy-shot-lock-extent extent nil))
  155.  
  156.  
  157. (defun lazy-shot-lock-extent (extent stealth)
  158.   "Font-lock the EXTENT. Called from redisplay-trigger functions and
  159. stealth locking functions"
  160.    (when (extent-live-p extent)
  161.      (let ((start (extent-start-position extent))
  162.        (end   (extent-end-position extent))
  163.        (buffer (extent-object extent)))
  164.        (delete-extent extent)
  165.        (lazy-shot-fontify-internal buffer start end
  166.                       (or lazy-shot-verbose 
  167.                       (and stealth
  168.                            lazy-shot-stealth-verbose))
  169.                       (if stealth "stealthy " "")))))
  170.  
  171. (defun lazy-shot-fontify-internal (buffer start end verbose message)
  172.   (save-excursion
  173.     ;; Should inhibit quit here
  174.     (set-buffer buffer) ;; with-current-buffer is silly here
  175.     ;; This magic should really go into font-lock-fonity-region
  176.     (goto-char start)
  177.     (setq start (point-at-bol))
  178.     (goto-char end)
  179.     (setq end (point-at-bol 2))
  180.     (lazy-shot-clean-up-extents start end)
  181.     ;; and a allow quit here
  182.     (if verbose
  183.     (display-message 'progress
  184.       (format "Lazy-shot fontifying %sfrom %s to %s in %s"
  185.              message start end buffer)))
  186.     (save-match-data
  187.       (font-lock-fontify-region start end))))
  188.  
  189. ;; Note this is suboptimal but works for now. It is not called that often.
  190. (defun lazy-shot-fontify-region (start end &optional buffer)
  191.   (lazy-shot-fontify-internal (or buffer (current-buffer))
  192.                     start end lazy-shot-verbose
  193.                     "on request "))
  194.  
  195. (defun lazy-shot-stealth-lock (buffer)
  196.   "Find an extent to lazy lock in buffer."
  197.   (if (buffer-live-p buffer)
  198.       (with-current-buffer buffer
  199.     (let ((extent t))
  200.       (while (and extent (sit-for lazy-shot-stealth-nice))
  201.         (setq extent
  202.           (or   ;; First after point
  203.            (map-extents (lambda (e n) e)  nil (point) nil nil nil
  204.                 'initial-redisplay-function
  205.                 'lazy-shot-redisplay-function)
  206.            ;; Then before it
  207.            (map-extents (lambda (e n) e) nil nil (point) nil nil
  208.                 'initial-redisplay-function
  209.                 'lazy-shot-redisplay-function)))
  210.         (if extent
  211.         (lazy-shot-lock-extent extent t)
  212.           (delete-itimer current-itimer)
  213.           (setq lazy-shot-stealth-timer nil)))))
  214.     (delete-itimer current-itimer)))
  215.     
  216. (defun lazy-shot-install-extent (spos epos &optional buffer)
  217.   "Make an extent that will lazy-shot if it is displayed."
  218.      (let ((extent (make-extent spos epos buffer)))
  219.        (when extent
  220.          (set-extent-initial-redisplay-function extent
  221.                        'lazy-shot-redisplay-function))
  222.        extent))
  223.  
  224.  
  225. (defun lazy-shot-install-extents (start end fontifying)
  226.   ;;
  227.   ;; Add hook if lazy-shot.el is deferring or is fontifying on scrolling.
  228.   (when fontifying
  229.     (save-excursion
  230.       (goto-char start)
  231.       (while (not (>= (point) end))
  232.     (setq start (point))
  233.     (goto-char (min end (+ start lazy-shot-step-size)))
  234.     (forward-line 1)
  235.     (lazy-shot-install-extent start (point))))))
  236.  
  237.  
  238. (defun lazy-shot-after-change-function (start end old-len)
  239.   (and lazy-shot-mode
  240.        ;; If it is too small an insert to notice, let font-lock take
  241.        ;; care of it.
  242.        (if (< (- end start) lazy-shot-step-size)
  243.        (font-lock-after-change-function start end old-len)
  244.      ;; If there is an extent of ours, get rid of it first, and
  245.      ;; expand the region that we should be extentifying.
  246.      (let ((extent (map-extents '(lambda (e b) e)
  247.                     nil start end nil nil
  248.                     'initial-redisplay-function
  249.                     'lazy-shot-redisplay-function)))
  250.        (if extent
  251.            (progn
  252.          (message "deleting extent")
  253.          (setq start (min start (extent-start-position extent))
  254.                end (max end (extent-end-position extent)))
  255.          (delete-extent extent))))
  256.      ;; Extentify the region.
  257.      (lazy-shot-install-extents start end font-lock-fontified))))
  258.  
  259.  
  260. (defun lazy-shot-install-timer (fontifying)
  261.   (when (and lazy-shot-stealth-time fontifying)
  262.     (make-variable-buffer-local 'lazy-shot-stealth-timer)
  263.     (setq lazy-shot-stealth-timer 
  264.       (start-itimer (format "lazy shot for %s" (current-buffer))
  265.              'lazy-shot-stealth-lock lazy-shot-stealth-time
  266.              lazy-shot-stealth-time
  267.              t t (current-buffer)))))
  268.  
  269.  
  270. (defun lazy-shot-install ()
  271.   (make-local-variable 'font-lock-fontified)
  272.   (setq font-lock-fontified (and lazy-shot-minimum-size
  273.                  (>= (buffer-size) lazy-shot-minimum-size))) 
  274.   (lazy-shot-install-extents (point-min) (point-max) font-lock-fontified)
  275.   (lazy-shot-install-timer font-lock-fontified)
  276.   (add-hook 'font-lock-after-fontify-buffer-hook
  277.         'lazy-shot-unstall-after-fontify)
  278.   ;; [Comment stolen from lazy-lock.el.]
  279.   ;; Fascistically remove font-lock's after-change-function and install
  280.   ;; our own.  We know better than font-lock what to do.  Otherwise,
  281.   ;; revert-buffer, insert-file, etc. cause full refontification of the
  282.   ;; entire changed area.
  283.   (remove-hook 'after-change-functions 'font-lock-after-change-function t)
  284.   (make-local-hook 'after-change-functions)
  285.   (add-hook 'after-change-functions 'lazy-shot-after-change-function nil t))
  286.  
  287. ;; Kludge needed untill lazy-lock-fontify-region is more intelligent
  288. (defun lazy-shot-unstall-after-fontify ()
  289.   (lazy-shot-unstall 1))
  290.  
  291. (defun lazy-shot-unstall (&optional no-fontify)
  292.   ;; Stop the timer
  293.   (when lazy-shot-stealth-timer
  294.     (delete-itimer lazy-shot-stealth-timer)
  295.     (setq lazy-shot-stealth-timer nil))
  296.   ;; Remove the extents.
  297.   (map-extents 
  298.      (lambda (e arg) (delete-extent e) nil) 
  299.      nil nil nil nil nil 'initial-redisplay-function 'lazy-shot-redisplay-function)
  300.   (when (and font-lock-mode (not no-fontify))
  301.     (save-restriction
  302.       (widen)
  303.       (lazy-shot-fontify-region (point-min) (point-max))))
  304.   (remove-hook 'after-change-functions 'lazy-shot-after-change-function t)
  305.   (if font-lock-mode
  306.       (add-hook 'after-change-functions 'font-lock-after-change-function
  307.         nil t)))
  308.  
  309. (provide 'lazy-shot)
  310.  
  311. ;;; lazy-shot.el ends here
  312.